using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SlasheneFramework.VisualStudio;
using SlasheneFramework;
using System.Collections.ObjectModel;
using System.IO;
using SlasheneFramework.UI;
using System.Windows.Input;
using System.Text.RegularExpressions;
using schemas.microsoft.com.developer.msbuild.Item2003;
using System.Xml.Linq;

namespace Genuilder.GUI
{

	public class GenuilderViewModel : NotifyPropertyChangedBase
	{
		public class GoCommand : ViewModelCommand<GenuilderViewModel>
		{
			public GoCommand(GenuilderViewModel vm)
				: base(vm)
			{
				vm.SelectedProjects.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(SelectedProjects_CollectionChanged);
			}

			void SelectedProjects_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
			{
				OnCanExecuteChanged();
			}
			public override bool CanExecute(object parameter)
			{
				return ViewModel.SelectedProjects.Count > 0;
			}

			public override void Execute(object parameter)
			{
				try
				{
					foreach(var file in ViewModel.SelectedProjects.Select(p => p.Project.Item))
					{
						bool modified = false;
						var project = schemas.microsoft.com.developer.msbuild.Item2003.Project.Load(file.FullName);
						var imports = project.Import;
						var importCommon = project.CommonImport;

						var genuilderPath = PathUtil.RelativePathTo(file.Directory.FullName, new FileInfo("Genuilder.dll").FullName);
						Reference genuilderReference = project.ItemGroup.SelectMany(g => g.Item).OfType<Reference>().FirstOrDefault(i => i.Include == "Genuilder");
						if(genuilderReference == null)
						{
							modified |= true;
							var itemGroupReferences = project.ItemGroup.First(g => g.Item.OfType<Reference>().Count() > 0);
							genuilderReference = new Reference();
							genuilderReference.Include = "Genuilder";
							var hintPath = new XElement("{http://schemas.microsoft.com/developer/msbuild/2003}HintPath");
							hintPath.Value = genuilderPath;
							genuilderReference.Untyped.Add(hintPath);
							itemGroupReferences.Item.Add(genuilderReference);
						}

						string toFile = "AllTargets.targets";
						modified |= importCommon.EnsureHasImportToFile(toFile, file.Directory.FullName, Position.After);
						if(modified)
							project.Save(file.FullName);
					}
					ViewModel.Done = true;
					ViewModel.Error = "";
				}
				catch(Exception ex)
				{
					ViewModel.Error = ex.Message;
				}
			}
		}

		public GenuilderViewModel()
		{
			this.Subscribe(() => this.SolutionFile).PropertyChanged += new SubscriptionEventHandler<string>(SolutionFileChanged);
			_Go = new GoCommand(this);
		}

		private bool _Done = false;
		public bool Done
		{
			get
			{
				return _Done;
			}
			private set
			{
				if(value != _Done)
				{
					_Done = value;
					OnPropertyChanged(() => this.Done);
				}
			}
		}

		void SolutionFileChanged(Subscription<string> sender, string newValue, string oldValue)
		{
			_SelectedProjects.Clear();
			_Projects.Clear();

			try
			{
				Solution solution = new Solution(new FileInfo(newValue));
				foreach(var project in solution.Projects)
				{
					var vm = new ProjectViewModel(project);
					vm.Subscribe(() => vm.IsSelected).PropertyChanged += new SubscriptionEventHandler<bool>(ProjectSelectedChanged);
					Projects.Add(vm);
				}
				_Error = "";
			}
			catch(Exception ex)
			{
				_Error = ex.Message;
			}
		}

		void ProjectSelectedChanged(Subscription<bool> sender, bool newValue, bool oldValue)
		{
			var vm = (ProjectViewModel)sender.Source;
			if(newValue)
				SelectedProjects.Add(vm);
			else
				SelectedProjects.Remove(vm);
		}


		private readonly ICommand _Go;
		public ICommand Go
		{
			get
			{
				return _Go;
			}
		}


		private String _Error;
		public String Error
		{
			get
			{
				return _Error;
			}
			set
			{
				if(value != _Error)
				{
					_Error = value;
					OnPropertyChanged(() => this.Error);
				}
			}
		}

		private String _SolutionFile;
		public String SolutionFile
		{
			get
			{
				return _SolutionFile;
			}
			set
			{
				if(value != _SolutionFile)
				{
					_SolutionFile = value;
					OnPropertyChanged(() => this.SolutionFile);
				}
			}
		}

		readonly ObservableCollection<ProjectViewModel> _SelectedProjects = new ObservableCollection<ProjectViewModel>();
		public ObservableCollection<ProjectViewModel> SelectedProjects
		{
			get
			{
				return _SelectedProjects;
			}
		}

		readonly ObservableCollection<ProjectViewModel> _Projects = new ObservableCollection<ProjectViewModel>();
		public ObservableCollection<ProjectViewModel> Projects
		{
			get
			{
				return _Projects;
			}
		}
	}
}
